namespace Radar
{
    using System;

    internal abstract class FactoryBuilder : IFactoryBuilder
    {
        private readonly IContainer container;
        private readonly Type implementationType;
        private readonly IConfigurationProvider configurationProvider;

        protected FactoryBuilder(Type implementationType, IContainer container, IConfigurationProvider configurationProvider)
        {
            if (implementationType == null) throw new ArgumentNullException("implementationType");
            if (container == null) throw new ArgumentNullException("container");
            if (configurationProvider == null) throw new ArgumentNullException("configurationProvider");

            ValidateImplementationType(implementationType);

            this.implementationType = implementationType;
            this.container = container;
            this.configurationProvider = configurationProvider;
        }

        public virtual Func<ResolveContext, object> GetFactoryMethod(params Type[] arguments)
        {
            var type = FindSuitableType(implementationType, arguments);

            var builder = ExpressionHelper.BuildConstructor(type, configurationProvider.Parameters, container);

            return configurationProvider.Lifetime.GetBuilder(builder);
        }

        protected abstract Type FindSuitableType(Type baseType, params Type[] arguments);

        protected virtual void ValidateImplementationType(Type type)
        {
            if (type.IsInterface)
                throw Error("Type {0} is interface", type);

            if (type.IsAbstract)
                throw Error("Type {0} is abstract or static.", type);
        }

        protected IocConfigurationException Error(string message, params object[] args)
        {
            return new IocConfigurationException(string.Format(message, args));
        }
    }
}